package org.tamal.struts.struts;

import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;

import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;

/**
 * This action is used to fetch different JSON arrays.
 * @author Tamal Kanti Nath
 */
@Results({
    @Result(name = JsonAction.ARRAY, type = "json",
        params = {"noCache", "true", "root", "list" }),
    @Result(name = JsonAction.STRING, type = "json",
        params = {"noCache", "true", "root", "string" }),
    @Result(name = Action.SUCCESS, type = "json",
        params = {"noCache", "true", "excludeNullProperties", "true" })
    })
@ParentPackage("json-default")
public final class JsonAction extends ActionSupport {

    /**
     * Array indicates the root element of the JSON is list.
     */
    protected static final String ARRAY = "array";

    /**
     * String indicates the root element of the JSON is string.
     */
    protected static final String STRING = "string";

    private static final long serialVersionUID = -731763780301937601L;

    private String query;
    private int page;
    private int size;
    private boolean desc;
    private String pattern;
    private List<String> list;
    private String string;

    /**
     * Produces result based of available queries.
     * <ul>
     *     <li>country</li>
     *     <li>language</li>
     *     <li>font</li>
     * </ul>
     * @return SUCCESS
     */
    @Override
    public String execute() {
        if ("country".equalsIgnoreCase(query)) {
            Set<String> countries = new HashSet<>();
            for (Locale l : Locale.getAvailableLocales()) {
                countries.add(l.getDisplayCountry());
            }
            countries.remove("");
            list = new ArrayList<>(countries.size());
            list.addAll(countries);
            return ARRAY;
        }

        if ("language".equalsIgnoreCase(query)) {
            Set<String> languages = new HashSet<>();
            for (Locale l : Locale.getAvailableLocales()) {
                languages.add(l.getDisplayCountry());
            }
            languages.remove("");
            list = new ArrayList<>(languages.size());
            list.addAll(languages);
            return ARRAY;
        }

        if ("font".equalsIgnoreCase(query)) {
            Set<String> fonts = new HashSet<>();
            for (Font f : GraphicsEnvironment.getLocalGraphicsEnvironment()
                    .getAllFonts()) {
                fonts.add(f.getFamily());
            }
            list = new ArrayList<>(fonts.size());
            list.addAll(fonts);
            return ARRAY;
        }

        if ("timezone".equalsIgnoreCase(query)) {
            list = new ArrayList<>();
            for (String tz : TimeZone.getAvailableIDs()) {
                list.add(tz);
            }
            return ARRAY;
        }
        if ("date".equalsIgnoreCase(query)) {
            DateFormat df;
            if (pattern == null) {
                df = new SimpleDateFormat();
                string = df.format(new Date());
            } else {
                df = new SimpleDateFormat(pattern);
            }
            string = df.format(new Date());
            return STRING;
        }
        return SUCCESS;
    }

    /**
     * Returns the result. Result is paged and ordered.
     * @return the result
     */
    public List<String> getList() {
        if (list == null) {
            return null;
        }
        Collections.sort(list);
        if (desc) {
            Collections.reverse(list);
        }
        if (page != 0) {
            if (size == 0) {
                size = 10;
            }
            List<String> temp = new ArrayList<>(size);
            for (int i = (page - 1) * size; i < page * size; ++i) {
                temp.add(list.get(i));
            }
            list = temp;
        }
        return list;
    }

    /**
     * Returns the string.
     * @return the string
     */
    public String getString() {
        return string;
    }

    /**
     * Sets the query.
     * @param query the query to set
     */
    public void setQuery(String query) {
        this.query = query;
    }

    /**
     * Sets the page.
     * @param page the page to set
     */
    public void setPage(int page) {
        this.page = page;
    }

    /**
     * Sets the size.
     * @param size the size to set
     */
    public void setSize(int size) {
        this.size = size;
    }

    /**
     * Sets the descending.
     * @param desc the descending to set
     */
    public void setDesc(boolean desc) {
        this.desc = desc;
    }

    /**
     * Sets the pattern.
     * @param pattern the pattern to set
     */
    public void setPattern(String pattern) {
        this.pattern = pattern;
    }
}
